package pl.edu.agh.nn.net;

import pl.edu.agh.nn.conf.IOConfiguration;
import pl.edu.agh.nn.data.producer.OutputDataProducer;
import pl.edu.agh.nn.data.provider.InputDataProvider;
import pl.edu.agh.nn.training.TrainingCase;
import pl.edu.agh.nn.training.TrainingCaseProvider;

public abstract class AbstractNetWithConfiguration implements INet {

	protected IOConfiguration ioConfiguration;

	@Override
	public void compute(InputDataProvider inputDataProvider, OutputDataProducer outputDataProducer) {
		while (inputDataProvider.hasData()) {
			double[] result = compute(inputDataProvider.nextData());
			outputDataProducer.produce(result);
		}
		inputDataProvider.finish();
		outputDataProducer.finish();
		if (ioConfiguration.getNetUtils() != null) {
			IOConfiguration copy = ioConfiguration;
			ioConfiguration = null;
			copy.getNetUtils().saveNetworkStructure(this);
		}
	}

	public abstract double[] compute(double[] input);

	@Override
	public void learn(TrainingCaseProvider trainingCaseProvider) {
		while (!isLearningFinished()) {
			TrainingCase trainingCase = trainingCaseProvider.nextData();
			double args[] = trainingCase.getTrainingData();
			double expected[] = trainingCase.getTestData();
			double result[] = learn(args, expected);
			if (ioConfiguration.getNetUtils() != null) {
				ioConfiguration.getNetUtils().computeAndAddError(expected, result);
			}
		}
		if (ioConfiguration.getNetUtils() != null) {
			ioConfiguration.getNetUtils().saveError();
		}
	}

	public abstract double[] learn(double[] train, double[] test);

	public abstract boolean isLearningFinished();

	public void setConfiguration(IOConfiguration ioConfiguration) {
		this.ioConfiguration = ioConfiguration;
	}

	@Override
	public IOConfiguration getConfiguration() {
		return this.ioConfiguration;
	}

}
